package ferp.android.social.ok;

import android.app.Activity;
import android.content.Intent;
import android.view.View;
import android.widget.ImageView;
import ferp.android.R;
import ferp.android.dialogs.ShareDialog;
import ferp.android.social.Connector;
import ferp.android.social.Post;
import ferp.core.game.Settings;
import ferp.core.log.Log;
import org.json.JSONObject;
import ru.ok.android.sdk.Odnoklassniki;
import ru.ok.android.sdk.OkTokenRequestListener;
import ru.ok.android.sdk.util.OkScope;

import java.util.HashMap;
import java.util.Map;

/**
 * User: olegs
 * Date: 5/14/13 6:22 PM
 */
public class OkConnector extends Connector
{
  public OkConnector()
  {
    LoginTokenRequestListener.instance = new LoginTokenRequestListener(this);
  }

  @Override
  public int getRequestCode()
  {
    return RequestCode.OK;
  }

  @Override
  public boolean isLoggedIn(Activity owner)
  {
    return ok(owner).hasAccessToken();
  }

  @Override
  public void onActivityResult(Activity owner, int result, Intent intent)
  {
    if (loginListener != null)
      loginListener.onLoginFinished(getRequestCode(), result == Activity.RESULT_OK);
  }

  @Override
  public void logout(Activity owner)
  {
    ok(owner).clearTokens(owner);
  }

  @Override
  public ImageView getLogoutIcon(ShareDialog dialog)
  {
    return (ImageView)(dialog.findViewById(R.id.social_frame_layout_ok).findViewById(R.id.dlg_share_logout));
  }

  @Override
  public ImageView getProgressIcon(ShareDialog dialog)
  {
    return (ImageView)(dialog.findViewById(R.id.social_frame_layout_ok).findViewById(R.id.dlg_share_clock));
  }

  @Override
  public ImageView getPostToastIcon(View toast)
  {
    return (ImageView)toast.findViewById(R.id.toast_post_result_ok);
  }

  @Override
  public ImageView getLogoutToastIcon(View toast)
  {
    return (ImageView)toast.findViewById(R.id.toast_social_logout_ok);
  }

  @Override
  protected void doLogin(Activity owner, int requestCode)
  {
    Log.debug(TAG, "Performing login");

    Odnoklassniki ok = ok(owner);

    ok.setTokenRequestListener(LoginTokenRequestListener.instance);
    ok.requestAuthorization(owner, false, OkScope.VALUABLE_ACCESS);
  }

  @Override
  protected PostError publish(Activity owner, Post post, Settings.Locale locale)
  {
    try
    {
      Map<String, String> params = new HashMap<String, String>();

      // fill request parameters
      params.put("comment", post.getText(owner.getResources().getString(R.string.post_playing_in_preferans)));
      params.put("linkUrl", Post.link(Settings.Locale.RUSSIAN));

      // publish
      JSONObject json = sendRequest(owner, params);

      // handle response
      long error = json.optLong(ERROR_CODE);

      if (error == OK)
      {
        Log.debug(TAG, "Publish succeeded");
        return null;
      }

      // if session expired try to refresh token and then republish
      if (error == ERROR_SESSION_EXPIRED)
      {
        json = republish(owner, params);

        // handle republish response
        error = json.optLong(ERROR_CODE);
        if (error == OK)
        {
          Log.debug(TAG, "Republish succeeded");
          return null;
        }

        Log.debug(TAG, "Republish failed " + json);
        return new PostError(error, "Republish failed");
      }

      Log.debug(TAG, "Publish failed " + json);
      return new PostError(error, "Publish failed");
    }
    catch (Exception e)
    {
      Log.error(TAG, e);
      return new PostError(-1, e.getMessage());
    }
  }

  private JSONObject sendRequest(Activity owner, Map<String, String> params) throws Exception
  {
    String response = ok(owner).request("share.addLink", params, "post");
    return new JSONObject(response);
  }

  private JSONObject republish(Activity owner, Map<String, String> params) throws Exception
  {
    synchronized (RefreshTokenRequestListener.instance)
    {
      Odnoklassniki ok = ok(owner);

      // assign RefreshTokenRequestListener as a listener to receive 'refresh token' notification
      ok.setTokenRequestListener(RefreshTokenRequestListener.instance);

      // refresh token
      Log.debug(TAG, "Session expired, refreshing token...");
      ok(owner).refreshToken(owner);

      // waiting for token refresh accomplishment
      RefreshTokenRequestListener.instance.wait(TOKEN_REFRESH_TIMEOUT);
    }

    // republish
    Log.debug(TAG, "Republishing...");
    return sendRequest(owner, params);
  }

  private Odnoklassniki ok(final Activity owner)
  {
    if (Odnoklassniki.hasInstance())
      return Odnoklassniki.getInstance(owner);

    Odnoklassniki ok = Odnoklassniki.createInstance(owner, APP_ID, APP_SECRET, APP_KEY);

    ok.setTokenRequestListener(LoginTokenRequestListener.instance);

    return ok;
  }

  // Production
  private static final String APP_ID = "176062464";
  private static final String APP_SECRET = "AFBBC84DDAEA831EB4AE7BD1";
  private static final String APP_KEY = "CBABIPHLABABABABA";

  // OK sample
/*
  private static final String APP_ID = "125497344";
  private static final String APP_SECRET = "E1B27795E3C2AF1A7B14CB11";
  private static final String APP_KEY = "CBABPLHIABABABABA";
*/

  // Sandbox
/*
  private static final String APP_ID = "1234432";
  private static final String APP_SECRET = "9414C5D614FF656FC91108E0";
  private static final String APP_KEY = "CBAHNDBBABABABABA";
*/

  // response OK code
  private static final long OK = 0;
  // session expired error code
  private static final long ERROR_SESSION_EXPIRED = 102;
  // 'error_code' string
  private static final String ERROR_CODE = "error_code";


  // token refresh timeout in milliseconds
  private static final long TOKEN_REFRESH_TIMEOUT = 3000L;

  private static final String TYPE = "Ok";
  private static final String TAG = Log.TAG + "/" + TYPE;

  // listener class for receiving 'login' notifications
  private static final class LoginTokenRequestListener implements OkTokenRequestListener
  {
    private LoginTokenRequestListener(OkConnector owner) {this.owner = owner;}

    @Override
    public void onSuccess(final String accessToken)
    {
      Log.debug(TAG, "Login succeeded, received token: " + accessToken);
      owner.loginListener.onLoginFinished(owner.getRequestCode(), true);
    }

    @Override
    public void onCancel()
    {
      Log.debug(TAG, "Login canceled");
      owner.loginListener.onLoginFinished(owner.getRequestCode(), false);
    }

    @Override
    public void onError()
    {
      Log.debug(TAG, "Login failed");
      owner.loginListener.onLoginFinished(owner.getRequestCode(), false);
    }

    private static LoginTokenRequestListener instance;

    private OkConnector owner;
  }

  // listener class for receiving 'refresh token' notifications
  private static final class RefreshTokenRequestListener implements OkTokenRequestListener
  {
    @Override
    public void onSuccess(final String accessToken)
    {
      Log.debug(TAG, "Token refresh succeeded, received token: " + accessToken);
      finish();
    }

    @Override
    public void onCancel()
    {
      Log.debug(TAG, "Token refresh canceled");
      finish();
    }

    @Override
    public void onError()
    {
      Log.debug(TAG, "Token refresh failed");
      finish();
    }

    private synchronized void finish()
    {
      notify();
    }

    private static final RefreshTokenRequestListener instance = new RefreshTokenRequestListener();
  }
}